package com.cxb.serviceorder.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cxb.internalcommon.constant.CommonStatusEnum;
import com.cxb.internalcommon.constant.IdentityConstant;
import com.cxb.internalcommon.constant.OrderConstants;
import com.cxb.internalcommon.dto.Car;
import com.cxb.internalcommon.dto.OrderInfo;
import com.cxb.internalcommon.dto.PriceRule;
import com.cxb.internalcommon.dto.ResponseResult;
import com.cxb.internalcommon.request.OrderRequest;
import com.cxb.internalcommon.request.PriceRuleIsNewRequest;
import com.cxb.internalcommon.responese.OrderDriverResponse;
import com.cxb.internalcommon.responese.TerminalResponse;
import com.cxb.internalcommon.util.RedisPrefixUtils;
import com.cxb.serviceorder.mapper.OrderInfoMapper;
import com.cxb.serviceorder.remote.ServiceDriverUserClient;
import com.cxb.serviceorder.remote.ServiceMapClient;
import com.cxb.serviceorder.remote.ServicePriceClient;
import com.cxb.serviceorder.remote.ServiceSsePushClient;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author 陈晓波
 * @since 2024-08-08
 */

@Service
@Slf4j
public class OrderInfoService  {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private ServicePriceClient servicePriceClient;

    @Autowired
    private ServiceDriverUserClient serviceDriverUserClient;

    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ServiceSsePushClient serviceSsePushClient;

    @Autowired
    RedissonClient redissonClient;

    /**
     * 新建订单
     * @param orderRequest
     * @return
     */
    public ResponseResult add(OrderRequest orderRequest){
        //测试当前城市是否有可用司机
        ResponseResult<Boolean> availableDriver = serviceDriverUserClient.isAvailableDriver(orderRequest.getAddress());
        log.info("测试城市是否有司机："+availableDriver.getData());
        if(!availableDriver.getData()){
            return ResponseResult.fail(CommonStatusEnum.CITY_DRIVER_EMPTY.getCode(),
                    CommonStatusEnum.CITY_DRIVER_EMPTY.getValue());
        }


        //判断计价规则是否最新
        PriceRuleIsNewRequest priceRuleIsNewRequest = new PriceRuleIsNewRequest();
        priceRuleIsNewRequest.setFareType(orderRequest.getFareType());
        priceRuleIsNewRequest.setFareVersion(orderRequest.getFareVersion());
        ResponseResult<Boolean> aNew = servicePriceClient.isNew(priceRuleIsNewRequest);
        if(!(aNew.getData())){
            return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_CHANGE.getCode(),
                    CommonStatusEnum.PRICE_RULE_CHANGE.getValue());
        }

        //判断下单设备是否黑名单
        if(isBlackDevice(orderRequest)){
            return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK.getCode(),
                    CommonStatusEnum.DEVICE_IS_BLACK.getValue());
        }

        //判断下单的城市和计价规则是否正常
        if(!isPriceRuleExists(orderRequest)){
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getCode(),
                    CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getValue());
        }

        //判断乘客是否有正在进行的订单
        if(isPassengerOrderGoingon(orderRequest.getPassengerId())>0){
            return ResponseResult.fail(CommonStatusEnum.ORDER_GOING_ON.getCode(),
                    CommonStatusEnum.ORDER_GOING_ON.getValue());
        }
        //创建订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest,orderInfo);
        //订单状态
        orderInfo.setOrderStatus(OrderConstants.ORDER_START);

        LocalDateTime now = LocalDateTime.now();
        orderInfo.setGmtCreate(now);
        orderInfo.setGmtModified(now);

        orderInfoMapper.insert(orderInfo);

        //定时任务的处理
        for(int i=0;i<6;i++){
            //派单
            int result = dispatchRealTimeOrder(orderInfo);
            if(result==1){
                break;
            }
            //等待20s
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
        return  ResponseResult.success();
    }

    /**
     * 判断是否是黑名单设备
     * @param orderRequest
     * @return
     */
    private boolean isBlackDevice(OrderRequest orderRequest){
        String deviceCode = orderRequest.getDeviceCode();
        String deviceCodeKey =  RedisPrefixUtils.blackDeviceCodePrefix + deviceCode;
        Boolean aBoolean = stringRedisTemplate.hasKey(deviceCodeKey);
        if(aBoolean){
            String s = stringRedisTemplate.opsForValue().get(deviceCodeKey);
            int i = Integer.parseInt(s);
            if(i>=2){
                //当前设备超过下单次数
                return true;
            }else{
                stringRedisTemplate.opsForValue().increment(deviceCodeKey);
            }
        }else{
            stringRedisTemplate.opsForValue().setIfAbsent(deviceCodeKey,"1",1L, TimeUnit.HOURS);
        }
        return false;
    }

    /**
     * 实时订单派单逻辑
     * @param orderInfo
     */
    public int dispatchRealTimeOrder(OrderInfo orderInfo){
        log.info("循环一次");
        int result =0;
        //起点经纬度
        String depLatitude = orderInfo.getDepLatitude();
        String depLongitude = orderInfo.getDepLongitude();

        String center = depLatitude +","+depLongitude;

        List<Integer> radiusList = new ArrayList<>();
        radiusList.add(2000);
        radiusList.add(4000);
        radiusList.add(5000);

        ResponseResult<List<TerminalResponse>> listResponseResult = null;
        //goto语句为了测试
        radius:
        for(int i=0;i<radiusList.size();i++){
            listResponseResult = serviceMapClient.aroundsearch(center, radiusList.get(i));
            log.info("在半径为"+radiusList.get(i)+"的范围寻找车辆,结果为："
            + JSONArray.fromObject(listResponseResult.getData()).toString());
            /**
             * [{"carId":1821080405923622914,"tid":"975347759"}]
             * 从car表中查询出车辆的carId和tid
             */
            //获得终端

            //解析终端
            List<TerminalResponse>  data = listResponseResult.getData();
            //JSONArray result = JSONArray.fromObject(listResponseResult.getData());
            for(int j=0;j<data.size();j++){
                TerminalResponse terminalResponse = data.get(j);
                //防止精度丢失
                Long carId = terminalResponse.getCarId();
                String longitude = terminalResponse.getLongitude();
                String latitude = terminalResponse.getLatitude();

                //查询是否有可派单的司机
                ResponseResult<OrderDriverResponse> availableDriver = serviceDriverUserClient.getAvailableDriver(carId);
                if(availableDriver.getCode()==CommonStatusEnum.AVAILABLE_DEIVER_EMPTY.getCode()){
                    log.info("没有车辆ID："+carId +",对应的司机");
                    continue;
                }else{
                    log.info("找到了正在出车的司机"+"车辆ID："+carId );
                    //根据解析的终端信息，查询车辆的信息
                    OrderDriverResponse data1 = availableDriver.getData();
                    Long driverId = data1.getDriverId();
                    String driverPhone = data1.getDriverPhone();
                    String licenseId = data1.getLicenseId();
                    String vehicleNo = data1.getVehicleNo();

                    //加入Redisson锁
                    String lockKey = (driverId + "").intern();
                    RLock lock = redissonClient.getLock(lockKey);
                    lock.lock();

                    //synchronized ((driverId+"").intern()){
                        //判断司机是否有正在进行的订单
                        if(isDriverOrderGoingon(driverId)>0){
                            //释放锁，防止死锁
                            lock.unlock();
                            continue ;
                        }
                        //找到符合的车辆，进行派单
                        //订单直接匹配司机
                        orderInfo.setDriverId(driverId);
                        orderInfo.setDriverPhone(driverPhone);

                        orderInfo.setReceiveOrderCarLatitude(latitude);
                        orderInfo.setReceiveOrderCarLongitude(longitude);

                        orderInfo.setCarId(carId);
                        orderInfo.setReceiveOrderTime(LocalDateTime.now());
                        orderInfo.setLicenseId(licenseId);
                        orderInfo.setVehicleNo(vehicleNo);
                        orderInfo.setOrderStatus(OrderConstants.DRIVER_RECEIVE_ORDER);

                        orderInfoMapper.updateById(orderInfo);

                        //通知司机乘客的信息和起点终点及其经纬度
                        JSONObject driverContent = new JSONObject();
                        driverContent.put("passengerId",orderInfo.getPassengerId());
                        driverContent.put("passengerPhone",orderInfo.getPassengerPhone());

                        driverContent.put("departure",orderInfo.getDeparture());
                        driverContent.put("depLongitude",orderInfo.getDepLongitude());
                        driverContent.put("depLatitude",orderInfo.getDepLatitude());

                        driverContent.put("destination",orderInfo.getDestination());
                        driverContent.put("destLongitude",orderInfo.getDestLongitude());
                        driverContent.put("destLatitude",orderInfo.getDestLatitude());
                        //推送给司机信息
                        serviceSsePushClient.push(driverId, IdentityConstant.DRIVER_IDENTITY,driverContent.toString());


                        //通知乘客，推送司机信息
                        JSONObject passengerContent = new JSONObject();
                        passengerContent.put("driverId",orderInfo.getDriverId());
                        passengerContent.put("driverPhone",orderInfo.getDriverPhone());
                        passengerContent.put("vehicleNo",orderInfo.getVehicleNo());

                        //调用driverUserService服务查询车辆信息
                        ResponseResult<Car> carById = serviceDriverUserClient.getCarById(carId);
                        Car carRemote = carById.getData();

                        passengerContent.put("brand",carRemote.getBrand());
                        passengerContent.put("model",carRemote.getModel());
                        passengerContent.put("vehicleColor",carRemote.getVehicleColor());

                        passengerContent.put("receiveOrderCarLongitude",orderInfo.getReceiveOrderCarLongitude());
                        passengerContent.put("receiveOrderCarLatitude",orderInfo.getReceiveOrderCarLatitude());
                        serviceSsePushClient.push(orderInfo.getPassengerId(),IdentityConstant.PASSENGER_IDENTITY,
                                passengerContent.toString());
                        result =1;
                        lock.unlock();
                        //若派单成功,则退出循环
                        break radius;
                    //}
                }
            }

        }
     return result;
    }

    /**
     * 根据城市编码和对应车型查询计价规则是否存在
     * @param orderRequest
     * @return
     */
    private boolean isPriceRuleExists(OrderRequest orderRequest){
        String fareType = orderRequest.getFareType();
        int index = fareType.indexOf("$");
        String cityCode = fareType.substring(0, index);
        String vehicleType = fareType.substring(index + 1);

        PriceRule priceRule = new PriceRule();
        priceRule.setCityCode(cityCode);
        priceRule.setVehicleType(vehicleType);

        ResponseResult<Boolean> booleanResponseResult = servicePriceClient.ifExists(priceRule);
        return booleanResponseResult.getData();
    }

    /**
     * 乘客是否有进行中的订单
     * @param passengerId
     * @return
     */
    public int isPassengerOrderGoingon(Long passengerId){
        //判断有正在进行的订单
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("passenger_id",passengerId);
        queryWrapper.and(wrapper->wrapper.eq("order_status",OrderConstants.ORDER_START)
                .or().eq("order_status",OrderConstants.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status",OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status",OrderConstants.PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstants.PASSENGER_GETOFF)
                .or().eq("order_status",OrderConstants.TO_START_PAY));

        Integer validNumber = orderInfoMapper.selectCount(queryWrapper);
        return validNumber;
    }

    /**
     * 司机是否有在进行中的订单
     * @param driverId
     * @return
     */
    public int isDriverOrderGoingon(Long driverId){
        //判断有正在进行的订单
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("driver_id",driverId);
        queryWrapper.and(wrapper->wrapper.eq("order_status",OrderConstants.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status",OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status",OrderConstants.PICK_UP_PASSENGER)
        );

        Integer validNumber = orderInfoMapper.selectCount(queryWrapper);
        log.info("司机:"+driverId+"正在进行的订单数量:"+validNumber);
        return validNumber;
    }

    /**
     * 去接乘客
     * @param orderRequest
     * @return
     */
    public ResponseResult toPickUpPassenger(OrderRequest orderRequest){
        log.info("ordeId:"+orderRequest.getOrderId());
        Long orderId = orderRequest.getOrderId();
        String toPickUpPassengerLatitude = orderRequest.getToPickUpPassengerLatitude();
        String toPickUpPassengerLongitude = orderRequest.getToPickUpPassengerLongitude();
        String toPickUpPassengerAddress = orderRequest.getToPickUpPassengerAddress();
        LocalDateTime toPickUpPassengerTime = orderRequest.getToPickUpPassengerTime();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);

        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);

        orderInfo.setToPickUpPassengerTime(toPickUpPassengerTime);
        orderInfo.setToPickUpPassengerAddress(toPickUpPassengerAddress);
        orderInfo.setToPickUpPassengerLongitude(toPickUpPassengerLongitude);
        orderInfo.setToPickUpPassengerLatitude(toPickUpPassengerLatitude);
        orderInfo.setOrderStatus(OrderConstants.DRIVER_TO_PICK_UP_PASSENGER);
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();

    }


    /**
     * 司机到达乘客上车点
     * @param orderRequest
     * @return
     */
    public ResponseResult arriverDeparture(OrderRequest orderRequest){

        Long orderId = orderRequest.getOrderId();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);

        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        orderInfo.setOrderStatus(OrderConstants.DRIVER_ARRIVED_DEPARTURE);
        orderInfo.setDriverArrivedDepartureTime(LocalDateTime.now());
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }
}
